//-----------------------------------------------------------------------

// <copyright file="BaseFieldDefinition.cs" company="Jamie Knight">

// Copyright (c) Jamie Knight. All rights reserved.

// </copyright>

//-----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Humanizer;

namespace DevKnightlie.WPF.AutoForm.FieldDefinitions
{
    /// <summary>
    /// Base class for Field Definition classes
    /// </summary>
    public class BaseFieldDefinition
    {

        /// <summary>
        /// Indicates how wide a control should be when appearing in certain layouts
        /// </summary>
        public enum StretchType
        {
            None, // Control should be the default width determined by the layout strategy
            Wide, // Control should be wider than normal
            Full, // Control should be as wide as the layout permits
            Remainder // Control should fill the remaining space on the current row
        }

        #region Private fields

        private string _propertyName;
        private string _title;
        private Control _inputControl = null;
        private Control _containerControl = null;
        private Control _labelControl = null;
        private bool _newline;
        private StretchType _stretchMode;
        private string _enabledPropertyName;
        private bool _invertEnabledState;


        #endregion


        #region Properties


        /// <summary>
        /// Sets or returns the name of the property being bound. Only used if PropertyInfo is null
        /// </summary>
        public String PropertyName
        {
            get { return PropertyInfo==null ? _propertyName : PropertyInfo.Name; }
            set { _propertyName = value; }
        }


        /// <summary>
        /// Sets or returns the PropertyInfo object for the property being bound
        /// </summary>
        public PropertyInfo PropertyInfo { get; set; }



        /// <summary>
        /// Sets or returns the name of a property which is bound to the Enabled property of the input control
        /// </summary>
        public String EnabledPropertyName
        {
            get { return _enabledPropertyName; }
            set { _enabledPropertyName = value; }
        }


        /// <summary>
        /// Sets or returns a value indicating that the value of the Enabled property should be inverted when applied to the enabled property of the input control
        /// </summary>
        public bool InvertEnabledState
        {
            get { return _invertEnabledState; }
            set { _invertEnabledState = value; }
        }


        /// <summary>
        /// Sets or returns the dockPanel control for this field, i.e. the control that is added to the form.
        /// </summary>
        /// <remarks>For most field types this will be the same as InputControl, i.e. the control itself. Some field types may build a dockPanel to hold the input field which will be held in this property.</remarks>
        public Control ContainerControl
        {
            get
            {
                if (_containerControl == null)
                {
                    BuildInputControl();
                }
                return _containerControl;
            }
            protected set
            {
                _containerControl = value;
            }
        }


        /// <summary>
        /// Sets or returns the input control for this field
        /// </summary>
        public Control InputControl
        {
            get
            {
                if (_inputControl == null)
                {
                    BuildInputControl();
                }
                return _inputControl;
            }
            protected set
            {
                _inputControl = value;
            }
        }


        /// <summary>
        /// Sets or returns the label control for this field
        /// </summary>
        public Control LabelControl
        {
            get
            {
                if (_labelControl == null)
                {
                    BuildLabelControl();
                }
                return _labelControl;
            }
            protected set
            {
                _labelControl = value;
            }
        }


        /// <summary>
        /// Sets or returns the Title to display near the input control
        /// </summary>
        public String Title
        {
            get
            {
                if (String.IsNullOrEmpty(_title) && !String.IsNullOrEmpty(PropertyName))
                {
                    return PropertyName.Humanize();
                }
                return _title;
            }
            set { _title = value; }
        }


        /// <summary>
        /// Indicates whether subsequent fields should begin on a new row in certain layouts.
        /// Affects GridLayoutStrategy and StackedLayoutStrategy.
        /// </summary>
        public bool Newline
        {
            get
            {
                return _newline;
            }
            set
            {
                _newline = value;
            }
        }

        /// <summary>
        /// Indicates how wide the control should be in certain layouts.
        /// Affects GridLayoutStrategy.
        /// </summary>
        public StretchType StretchMode
        {
            get { return _stretchMode; }
            set { _stretchMode = value; }
        }
        #endregion


        #region Methods

        /// <summary>
        /// Creates the input control for this field
        /// </summary>
        /// <returns></returns>
        public virtual void BuildInputControl()
        {
            InputControl = null;
            ContainerControl = null;
        }


        /// <summary>
        /// Creates and returns the label for this field
        /// </summary>
        /// <returns></returns>
        public virtual void BuildLabelControl()
        {
            if (!String.IsNullOrWhiteSpace(Title))
            {
                Label result = new Label()
                {
                    Content = Title,
                    Target = _inputControl
                };
                _labelControl = result;
            }
        }


        /// <summary>
        /// Removes references to all related controls
        /// </summary>
        public void Reset()
        {
            ContainerControl = null;
            InputControl = null;
            LabelControl = null;
        }


        /// <summary>
        /// Set up IsEnabled binding on the given control where necessary
        /// </summary>
        /// <param name="control">The control to setup</param>
        protected bool SetupEnabledBinding(UIElement control)
        {
            if (String.IsNullOrWhiteSpace(EnabledPropertyName)) return false;
            Binding enabledBinding = new Binding(EnabledPropertyName);
            if (InvertEnabledState)
            {
                enabledBinding.Converter = new InverseBooleanConverter();
            }
            BindingOperations.SetBinding(control, UIElement.IsEnabledProperty, enabledBinding);
            return true;
        }

        #endregion

    }
}
